package jmine.tec.utils.reflection.fast.asm;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import jmine.tec.utils.reflection.fast.FastClass;
import jmine.tec.utils.reflection.fast.FastClassFactory;
import jmine.tec.utils.reflection.fast.FastMethodNoArgs;
import jmine.tec.utils.reflection.fast.reflection.ReflectionFastClassFactory;

@SuppressWarnings("unused")
public class Performance {

    private static final OpenClassLoader cl = new OpenClassLoader();

    private int status;

    private final AtomicInteger stat = new AtomicInteger();

    public void simpleMethod() {
        // stat.getAndIncrement();
        this.status++;
        // return stat.getAndIncrement();
    }

    public void verify() throws Exception {
        FastMethodCompiler compiler = new FastMethodCompiler(cl);
        FastClassFactory fac;
        fac = new AsmFastClassFactory(cl);
        fac = new ReflectionFastClassFactory();
        FastClass fastClass = fac.forClass(Performance.class);
        FastMethodNoArgs method = (FastMethodNoArgs) fastClass.findMethod("simpleMethod");
        CompiledFastMethod cmpMet = compiler.compileAndLoad(method);
        // warm up
        Object p = new Performance();
        final Performance target = (Performance) p;
        for (int i = 0; i < 15000; i++) {
            method.invokeNoArgs(p);
            cmpMet.invokeNoArgs(p);
            target.simpleMethod();
        }
        long t0, nanos, time;
        double s;
        final int max = 5000000;
        System.out.println("\nfastMethod.invoke");
        t0 = System.nanoTime();
        for (int i = 0; i < max; i++) {
            method.invokeNoArgs(p);
        }
        nanos = System.nanoTime() - t0;
        time = TimeUnit.NANOSECONDS.toMillis(nanos);
        s = (double) nanos / (double) max;
        System.out.println("total time: " + time);
        System.out.println("avg time: " + s);

        System.out.println("\ndirect call");
        t0 = System.nanoTime();
        for (int i = 0; i < max; i++) {
            target.simpleMethod();
        }
        nanos = System.nanoTime() - t0;
        time = TimeUnit.NANOSECONDS.toMillis(nanos);
        s = (double) nanos / (double) max;
        System.out.println("total time: " + time);
        System.out.println("avg time: " + s);

        System.out.println("\ncompiled method");
        t0 = System.nanoTime();
        for (int i = 0; i < max; i++) {
            cmpMet.invokeNoArgs(p);
        }
        nanos = System.nanoTime() - t0;
        time = TimeUnit.NANOSECONDS.toMillis(nanos);
        s = (double) nanos / (double) max;
        System.out.println("total time: " + time);
        System.out.println("avg time: " + s);

    }

    public static void main(String[] args) throws Exception {
        // FastClassFactory fac = new ReflectionFastClassFactory();
        Performance performance = new Performance();
        performance.verify();

    }

}
